---
title: MergeController
summary: Merges multiple source documents into a single PDF output.
status: draft
owner: Not determined from source
last_reviewed: 2026-09-17
library: PdfAPI
reference_type: embedded
---

# MergeController

`MergeController` converts any non-PDF input documents to PDF and merges all inputs into a single PDF output.

| Field | Value |
| --- | --- |
| **Controller** | `MergeController` |
| **Base** | `System.Web.Http.ApiController` |
| **Route prefix** | `[RoutePrefix("v1")]` |
| **Source** | `PdfAPI\Controllers\v1\MergeController.cs` |
| **Controller-level authorization** | None in code |
| **Error handling** | Per-action `try`/`catch` + `ILogService.LogException`; the pre-`try` `Enforce.ArgumentNotNull` guard is outside the catch and escapes to the framework |
| **Endpoints** | 1 |

---

## POST v1/merge

Merges the documents described in a `MergeRequest` into a single PDF, converting any non-PDF input first, then returns the merged result.

| Field | Value |
| --- | --- |
| **HTTP verb** | `POST` |
| **Resolved route** | `v1/merge` |
| **Route composition** | `[RoutePrefix("v1")]` + `[Route("merge")]` |
| **Action** | `Merge(MergeRequest request)` |
| **Return type** | `IHttpActionResult` (`Ok(result)`) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Idempotent** | No — each call creates a new tracking record and a new merged output document* |
| **Operation** | [OP-MERGE-DOCUMENTS](../operations/op-merge-documents.md) |

### Parameters

| Name | In | Type | Required | Default | Binding | Purpose |
| --- | --- | --- | --- | --- | --- | --- |
| `request` | Body | `PdfAPI.Core.MergeRequest` | Yes | — | Implicit complex-type body binding* | The set of source documents and page ranges to merge |

### Request

| Field | Value |
| --- | --- |
| **DTO** | `PdfAPI.Core.MergeRequest` (`PdfAPI.Core\Request\MergeRequest.cs`) |
| **Media type** | `application/json` |
| **Validation** | `Enforce.ArgumentNotNull(request, "request")` runs before the `try` block ([BR-PDFAPI-001](../business-rules.md#br-pdfapi-001-null-merge-request-bypasses-the-error-envelope)) |

| Property | Type | Required | Constraints | Purpose |
| --- | --- | --- | --- | --- |
| `DocumentRanges` | `DocumentRange[]` | Yes | — | The documents (and optional page ranges) to merge, in order |
| `Options` | `PdfOptions` | No | Defaulted to a new `PdfOptions` when omitted ([BR-PDFAPI-002](../business-rules.md#br-pdfapi-002-default-merge-options-substitution)) | Output format and processing options |

### Response

| Field | Value |
| --- | --- |
| **DTO** | `PdfAPI.Core.PdfResult` |
| **Media type** | `application/json` |

| Property | Type | Nullable | Purpose |
| --- | --- | --- | --- |
| `Status` | `PdfStatus` | No | Result of the merge |
| `Document` | `Document` | Yes | The merged output document |

### Status codes

| Status | Condition | Body |
| --- | --- | --- |
| `200 OK` | Merge succeeds, or an in-`try` failure is caught and returned as a failed `PdfResult` | `PdfResult` |

### Errors

| Error status | Trigger | Produced by | Body |
| --- | --- | --- | --- |
| `500 Internal Server Error` | `request` is `null` — `Enforce.ArgumentNotNull` throws before the `try` block and escapes to the framework ([BR-PDFAPI-001](../business-rules.md#br-pdfapi-001-null-merge-request-bypasses-the-error-envelope)) | Framework (uncaught exception, `IncludeErrorDetailPolicy.Always`) | Exception detail |

The `Body` column above describes only the pre-envelope detail produced by the framework.
Every response also passes through the globally registered `ApiResponseHandler` message handler (`SAIF.Web.API` package), which wraps or post-processes the HTTP response for the whole service. That handler's exact outer envelope shape is implemented inside the package and is not visible in this repository — see [Endpoints: Error response shape](../endpoints.md#error-response-shape).

### Business rules

- [BR-PDFAPI-001](../business-rules.md#br-pdfapi-001-null-merge-request-bypasses-the-error-envelope) — a null merge request body fails as a framework error rather than a `PdfResult`.
- [BR-PDFAPI-002](../business-rules.md#br-pdfapi-002-default-merge-options-substitution) — when a merge request omits `Options`, a default `PdfOptions` is substituted.
- [BR-PDFAPI-006](../business-rules.md#br-pdfapi-006-merge-aborts-entirely-on-pre-conversion-failure) — in a merge, every non-PDF input is converted to PDF first; if any pre-conversion fails, the whole merge is abandoned.
- [BR-PDFAPI-007](../business-rules.md#br-pdfapi-007-pdf-a-output-silently-downgraded) — when PDF/A output is requested but the produced document fails PDF/A validation, the result is silently downgraded to `PdfFormat.Pdf`.

### Authorization

No authorization attribute or programmatic check is present. See [Authentication and authorization](../authentication-authorization.md).

### Side effects and idempotency

| Aspect | Finding |
| --- | --- |
| Records written | `PDFTracking`, when tracking is enabled for the request (see [Data model](../data-model.md)) |
| Downstream calls | None identified |
| Files or messages produced | Merged output document written to `pdfapi.rootdirectory` |
| Repeat-call behavior | Each call creates a new tracking record and a new merged output document* |

### Example

```http
POST v1/merge HTTP/1.1
Host: <host>
Content-Type: application/json

{
  "DocumentRanges": [
    { "Document": { "File": "<base64 bytes a>" } },
    { "Document": { "File": "<base64 bytes b>" } }
  ]
}
```

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "Status": "Succeeded",
  "Document": { "FileName": "merged.pdf" }
}
```

---

## Related documentation
- [API index](../index.md)
- [Overview](../overview.md)
- [Architecture](../architecture.md)
- [Endpoints](../endpoints.md)
- [Authentication and authorization](../authentication-authorization.md)
- [Dependencies](../dependencies.md)
- [Configuration](../configuration.md)
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Data model](../data-model.md)
- [Operational runbook](../operational-runbook.md)
- [Tech debt](../tech-debt.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with `**` could not be confirmed; treat as unknown until verified.

## Sources
- PdfAPI\Controllers\v1\MergeController.cs
- PdfAPI.Core\Request\MergeRequest.cs
- PdfAPI.Core\PdfOptions.cs
- PdfAPI.Core\PdfResult.cs
